/*
 * 描          述:  <描述>
 * 修  改   人:  
 * 修改时间:  
 * <修改描述:>
 */
package com.tx.component.attachment.service;

import java.beans.PropertyDescriptor;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Column;

import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.tx.component.attachment.dao.AttachmentInstanceDao;
import com.tx.component.attachment.model.AttachmentInstance;
import com.tx.core.exceptions.util.AssertUtils;
import com.tx.core.paged.model.PagedList;
import com.tx.core.querier.model.Querier;
import com.tx.core.querier.model.QuerierBuilder;

/**
 * AttachmentInstance的业务层[AttachmentInstanceService]
 * <功能详细描述>
 * 
 * @author  
 * @version [版本号]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class AttachmentInstanceService implements InitializingBean {
    
    @SuppressWarnings("unused")
    private Logger logger = LoggerFactory
            .getLogger(AttachmentInstanceService.class);
    
    private AttachmentInstanceDao attachmentInstanceDao;
    
    private AttachmentTagService attachmentTagService;
    
    /** 所属模块 */
    private String module;
    
    /** <默认构造函数> */
    public AttachmentInstanceService() {
        super();
    }
    
    /** <默认构造函数> */
    public AttachmentInstanceService(String module,
            AttachmentInstanceDao attachmentInstanceDao,
            AttachmentTagService attachmentTagService) {
        super();
        this.module = module;
        this.attachmentInstanceDao = attachmentInstanceDao;
        this.attachmentTagService = attachmentTagService;
    }
    
    /**
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        AssertUtils.notEmpty(module, "module is empty.");
    }
    
    /**
     * 保存附件<br/>
     * <功能详细描述>
     * @param attachment
     * @return [参数说明]
     * 
     * @return AttachmentInstance [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public void save(AttachmentInstance attachment) {
        AssertUtils.notNull(attachment, "attachment is null.");
        AssertUtils.notEmpty(attachment.getCatalog(),
                "attachment.catalog is empty.");
        AssertUtils.notEmpty(attachment.getRelativePath(),
                "attachment.relativePath is empty.");
        //categoryKey,businessKey,typeKey
        AssertUtils.notEmpty(attachment.getCategoryKey(),
                "attachment.categoryKey is empty.");
        AssertUtils.notEmpty(attachment.getBusinessKey(),
                "attachment.businessKey is empty.");
        
        AttachmentInstance dbAttachmentInstance = null;
        //查询实例
        if (!StringUtils.hasText(attachment.getId())) {
            dbAttachmentInstance = findByRelativePath(
                    attachment.getRelativePath(),
                    attachment.getCatalog());
        } else {
            dbAttachmentInstance = findById(attachment.getId());
        }
        
        //如果实例为空
        if (dbAttachmentInstance == null) {
            //插入
            insert(attachment);
        } else {
            //更新
            updateById(dbAttachmentInstance.getId(), attachment);
        }
    }
    
    /**
     * 新增AttachmentInstance实例<br/>
     * 将attachmentInstance插入数据库中保存
     * 1、如果attachmentInstance 为空时抛出参数为空异常
     * 2、如果attachmentInstance 中部分必要参数为非法值时抛出参数不合法异常
     * 
     * @param attachmentInstance [参数说明]
     * @return void [返回类型说明]
     * @exception throws
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public void insert(AttachmentInstance attachment) {
        //验证参数是否合法
        AssertUtils.notNull(attachment, "attachment is null.");
        AssertUtils.notEmpty(attachment.getCatalog(),
                "attachment.catalog is empty.");
        AssertUtils.notEmpty(attachment.getRelativePath(),
                "attachment.relativePath is empty.");
        //categoryKey,businessKey,typeKey
        AssertUtils.notEmpty(attachment.getCategoryKey(),
                "attachment.categoryKey is empty.");
        AssertUtils.notEmpty(attachment.getBusinessKey(),
                "attachment.businessKey is empty.");
        
        if (!StringUtils.hasLength(attachment.getFilename())) {
            attachment.setFilename(
                    StringUtils.getFilename(attachment.getRelativePath()));
        }
        if (!StringUtils.hasLength(attachment.getFilenameExtension())) {
            attachment.setFilenameExtension(StringUtils
                    .getFilenameExtension(attachment.getRelativePath()));
        }
        attachment.setModule(this.module);
        //为添加的数据需要填入默认值的字段填入默认值
        attachment.setLastUpdateDate(new Date());
        attachment.setCreateDate(new Date());
        
        //调用数据持久层对实例进行持久化操作
        this.attachmentInstanceDao.insert(attachment);
        //如果存在tags则批量更新tags
        if (!CollectionUtils.isEmpty(attachment.getTags())) {
            attachment.getTags().stream().forEach(t -> {
                t.setAttachmentId(attachment.getId());
            });
            this.attachmentTagService.batchInsert(attachment.getTags());
        }
    }
    
    /**
     * 根据id删除AttachmentInstance实例
     * 1、如果入参数为空，则抛出异常
     * 2、执行删除后，将返回数据库中被影响的条数 > 0，则返回true
     *
     * @param id
     * @return boolean 删除的条数>0则为true [返回类型说明]
     * @exception throws 
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public boolean deleteById(String id) {
        AssertUtils.notEmpty(id, "id is empty.");
        
        AttachmentInstance condition = new AttachmentInstance();
        condition.setId(id);
        
        int resInt = this.attachmentInstanceDao.delete(condition);
        boolean flag = resInt > 0;
        if (flag) {
            this.attachmentTagService.deleteByAttachmentId(id);
        }
        return flag;
    }
    
    /**
     * 根据id查询AttachmentInstance实例
     * 1、当id为empty时抛出异常
     *
     * @param id
     * @return AttachmentInstance [返回类型说明]
     * @exception throws
     * @see [类、类#方法、类#成员]
     */
    public AttachmentInstance findById(String id) {
        AssertUtils.notEmpty(id, "id is empty.");
        
        AttachmentInstance condition = new AttachmentInstance();
        condition.setId(id);
        
        AttachmentInstance res = this.attachmentInstanceDao.find(condition);
        if (res != null) {
            //查询tag并设置入
            res.setTags(this.attachmentTagService
                    .queryListByAttachmentId(res.getId(), null));
        }
        return res;
    }
    
    /**
     * @param catalog
     * @param relativePath
     * @return
     */
    public AttachmentInstance findByRelativePath(String relativePath,
            String catalog) {
        AssertUtils.notEmpty(relativePath, "relativePath is empty.");
        AssertUtils.notEmpty(catalog, "catalog is empty.");
        
        AttachmentInstance condition = new AttachmentInstance();
        condition.setModule(this.module);
        condition.setCatalog(catalog);
        condition.setRelativePath(relativePath);
        
        AttachmentInstance res = this.attachmentInstanceDao.find(condition);
        if (res != null) {
            //查询tag并设置入
            res.setTags(this.attachmentTagService
                    .queryListByAttachmentId(res.getId(), null));
        }
        return res;
    }
    
    /**
     * 查询AttachmentInstance实例列表
     * <功能详细描述>
     * @param params      
     * @return [参数说明]
     * 
     * @return List<AttachmentInstance> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public List<AttachmentInstance> queryList(Map<String, Object> params) {
        //生成查询条件
        params = params == null ? new HashMap<String, Object>() : params;
        params.put("module", this.module);
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        List<AttachmentInstance> resList = this.attachmentInstanceDao
                .queryList(params);
        resList.stream().forEach(t -> {
            t.setTags(this.attachmentTagService
                    .queryListByAttachmentId(t.getId(), null));
        });
        
        return resList;
    }
    
    /**
     * 查询AttachmentInstance实例列表
     * <功能详细描述>
     * @param querier      
     * @return [参数说明]
     * 
     * @return List<AttachmentInstance> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public List<AttachmentInstance> queryList(Querier querier) {
        //生成查询条件
        querier = querier == null ? QuerierBuilder.newInstance().querier()
                : querier;
        querier.getParams().put("module", this.module);
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        List<AttachmentInstance> resList = this.attachmentInstanceDao
                .queryList(querier);
        resList.stream().forEach(t -> {
            t.setTags(this.attachmentTagService
                    .queryListByAttachmentId(t.getId(), null));
        });
        
        return resList;
    }
    
    /**
     * 分页查询AttachmentInstance实例列表
     * <功能详细描述>
     * @param params    
     * @param pageIndex 当前页index从1开始计算
     * @param pageSize 每页显示行数
     * 
     * <功能详细描述>
     * @return [参数说明]
     * 
     * @return List<AttachmentInstance> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public PagedList<AttachmentInstance> queryPagedList(
            Map<String, Object> params, int pageIndex, int pageSize) {
        //生成查询条件
        params = params == null ? new HashMap<String, Object>() : params;
        params.put("module", this.module);
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        PagedList<AttachmentInstance> resPagedList = this.attachmentInstanceDao
                .queryPagedList(params, pageIndex, pageSize);
        resPagedList.getList().stream().forEach(t -> {
            t.setTags(this.attachmentTagService
                    .queryListByAttachmentId(t.getId(), null));
        });
        
        return resPagedList;
    }
    
    /**
     * 分页查询AttachmentInstance实例列表
     * <功能详细描述>
     * @param querier    
     * @param pageIndex 当前页index从1开始计算
     * @param pageSize 每页显示行数
     * 
     * <功能详细描述>
     * @return [参数说明]
     * 
     * @return List<AttachmentInstance> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public PagedList<AttachmentInstance> queryPagedList(Querier querier,
            int pageIndex, int pageSize) {
        //生成查询条件
        querier = querier == null ? QuerierBuilder.newInstance().querier()
                : querier;
        querier.getParams().put("module", this.module);
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        PagedList<AttachmentInstance> resPagedList = this.attachmentInstanceDao
                .queryPagedList(querier, pageIndex, pageSize);
        resPagedList.getList().stream().forEach(t -> {
            t.setTags(this.attachmentTagService
                    .queryListByAttachmentId(t.getId(), null));
        });
        
        return resPagedList;
    }
    
    /**
     * 查询AttachmentInstance实例数量<br/>
     * <功能详细描述>
     * @param params      
     * @return [参数说明]
     * 
     * @return List<AttachmentInstance> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public int count(Map<String, Object> params) {
        //生成查询条件
        params = params == null ? new HashMap<String, Object>() : params;
        params.put("module", this.module);
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        int res = this.attachmentInstanceDao.count(params);
        
        return res;
    }
    
    /**
     * 查询AttachmentInstance实例数量<br/>
     * <功能详细描述>
     * @param querier      
     * @return [参数说明]
     * 
     * @return List<AttachmentInstance> [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public int count(Querier querier) {
        //生成查询条件
        querier = querier == null ? QuerierBuilder.newInstance().querier()
                : querier;
        querier.getParams().put("module", this.module);
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        int res = this.attachmentInstanceDao.count(querier);
        
        return res;
    }
    
    /**
     * 判断AttachmentInstance实例是否已经存在<br/>
     * <功能详细描述>
     * @param key2valueMap
     * @param excludeId
     * @return
     * 
     * @return int [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public boolean exists(Map<String, String> key2valueMap, String excludeId) {
        AssertUtils.notEmpty(key2valueMap, "key2valueMap is empty");
        
        //生成查询条件
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("module", this.module);
        params.putAll(key2valueMap);
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        int res = this.attachmentInstanceDao.count(params, excludeId);
        
        return res > 0;
    }
    
    /**
     * 判断AttachmentInstance实例是否已经存在<br/>
     * <功能详细描述>
     * @param key2valueMap
     * @param excludeId
     * @return
     * 
     * @return int [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public boolean exists(Querier querier, String excludeId) {
        AssertUtils.notNull(querier, "querier is null.");
        querier.getParams().put("module", this.module);
        
        //根据实际情况，填入排序字段等条件，根据是否需要排序，选择调用dao内方法
        int res = this.attachmentInstanceDao.count(querier, excludeId);
        
        return res > 0;
    }
    
    /**
     * 根据id更新AttachmentInstance实例<br/>
     * <功能详细描述>
     * @param attachmentInstance
     * @return [参数说明]
     * 
     * @return boolean [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public boolean updateById(String id, Map<String, Object> updateRowMap) {
        //验证参数是否合法，必填字段是否填写
        AssertUtils.notEmpty(id, "id is empty.");
        AssertUtils.notEmpty(updateRowMap, "updateRowMap is empty.");
        
        updateRowMap.put("lastUpdateDate", new Date());
        boolean flag = this.attachmentInstanceDao.update(id, updateRowMap);
        //如果需要大于1时，抛出异常并回滚，需要在这里修改
        return flag;
    }
    
    /**
     * 根据id更新AttachmentInstance实例<br/>
     * <功能详细描述>
     * @param attachment
     * @return [参数说明]
     * 
     * @return boolean [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public boolean updateById(String id, AttachmentInstance attachment) {
        //验证参数是否合法，必填字段是否填写
        AssertUtils.notNull(attachment, "attachmentInstance is null.");
        AssertUtils.notEmpty(id, "id is empty.");
        
        if (!StringUtils.hasLength(attachment.getFilename())) {
            attachment.setFilename(
                    StringUtils.getFilename(attachment.getRelativePath()));
        }
        if (!StringUtils.hasLength(attachment.getFilenameExtension())) {
            attachment.setFilenameExtension(StringUtils
                    .getFilenameExtension(attachment.getRelativePath()));
        }
        //生成需要更新字段的hashMap
        Map<String, Object> updateRowMap = new HashMap<String, Object>();
        //需要更新的字段
        updateRowMap.put("size", attachment.getSize());
        updateRowMap.put("deleted", attachment.isDeleted());
        updateRowMap.put("deleteDate", attachment.getDeleteDate());
        updateRowMap.put("filename", attachment.getFilename());
        updateRowMap.put("originalFilename", attachment.getOriginalFilename());
        updateRowMap.put("filenameExtension",
                attachment.getFilenameExtension());
        updateRowMap.put("lastUpdateDate", new Date());
        
        boolean flag = this.attachmentInstanceDao.update(id, updateRowMap);
        //如果需要大于1时，抛出异常并回滚，需要在这里修改
        //如果存在tags则批量更新tags
        if (flag && !CollectionUtils.isEmpty(attachment.getTags())) {
            attachment.getTags().forEach(t -> {
                t.setAttachmentId(id);
            });
            this.attachmentTagService.batchSave(id, attachment.getTags());
        }
        return flag;
    }
    
    /**
     * 根据id更新AttachmentInstance实例<br/>
     * <功能详细描述>
     * @param attachmentInstance
     * @return [参数说明]
     * 
     * @return boolean [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public boolean updateById(AttachmentInstance attachmentInstance) {
        //验证参数是否合法，必填字段是否填写
        AssertUtils.notNull(attachmentInstance, "attachmentInstance is null.");
        AssertUtils.notEmpty(attachmentInstance.getId(),
                "attachmentInstance.id is empty.");
        
        Map<String, Object> updateRowMap = new HashMap<String, Object>();
        BeanWrapper bw = PropertyAccessorFactory
                .forBeanPropertyAccess(attachmentInstance);
        for (PropertyDescriptor pd : bw.getPropertyDescriptors()) {
            if (pd.getWriteMethod() == null || pd.getReadMethod() == null) {
                continue;
            }
            if ("id".equals(pd.getName())) {
                continue;
            }
            TypeDescriptor td1 = bw.getPropertyTypeDescriptor(pd.getName());
            if (td1.hasAnnotation(Column.class)
                    && !td1.getAnnotation(Column.class).updatable()) {
                continue;
            }
            updateRowMap.put(pd.getName(), bw.getPropertyValue(pd.getName()));
        }
        boolean flag = updateById(attachmentInstance.getId(), updateRowMap);
        //如果需要大于1时，抛出异常并回滚，需要在这里修改
        return flag;
    }
    
    /**
     * 根据附件ID将附件移到历史表中<br/>
     * <功能详细描述>
     * @param attachmentId
     * @return [参数说明]
     * 
     * @return boolean [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    @Transactional
    public boolean moveToHisById(String attachmentId) {
        AssertUtils.notEmpty(attachmentId, "attachmentId is empty.");
        
        //根据id查询文件定义
        AttachmentInstance attachment = findById(attachmentId);
        if (attachment == null) {
            return false;
        }
        //插入历史表(可当做回收站使用)
        Date now = new Date();
        attachment.setDeleted(true);
        attachment.setDeleteDate(now);
        this.attachmentInstanceDao.insertToHis(attachment);
        
        //删除当前表中的数据
        boolean flag = deleteById(attachmentId);
        if (flag) {
            this.attachmentTagService.moveToHisByAttachmentId(attachmentId);
        }
        return flag;
    }
}
